package org.ranch.api.security.service.impl;

import org.apache.commons.lang.StringUtils;
import org.ranch.api.security.RanchUserDetails;
import org.ranch.api.security.service.AuthenticationService;
import org.ranch.api.security.service.RanchUserDetailsService;
import org.ranch.api.security.util.RanchSecurityUtil;
import org.ranch.dao.UserDAO;
import org.ranch.model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;

/**
 * Implementation class for {@link AuthenticationService} interface
 * 
 */
@Service("authenticationService")
public class AuthenticationServiceImpl implements AuthenticationService {

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private RanchUserDetailsService mohrUserDetailsService;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.mak.cis.mohr.api.security.service.AuthenticationService#authenticate
     * (java .lang.String, java.lang.String)
     */
    @Override
    public User authenticate(String username, String password,
	    boolean attachUserToSecurityContext) {
	User user = null;
	if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
	    user = userDAO.searchUniqueByPropertyEqual("username", username);
	    if (user != null && isValidUserPassword(user, password)) {
		if (attachUserToSecurityContext) {
		    RanchUserDetails userDetails = (RanchUserDetails) mohrUserDetailsService
			    .getUserDetailsForUser(user);
		    if (userDetails != null) {
			RanchSecurityUtil.setSecurityContext(userDetails);
		    }
		} else {
		    return user;
		}
	    } else {
		log.error("Access denied for " + user.getUsername());
		throw new AccessDeniedException("password and username mismatch.");
	    }
	}

	return user;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mak.cis.mohr.api.security.service.AuthenticationService#
     * isValidUserPassword (java.lang.String, java.lang.String)
     */
    @Override
    public Boolean isValidUserPassword(User user, String password) {

	if (user == null || StringUtils.isBlank(password) || StringUtils.isBlank(user.getSalt())) {
	    // we don't accept empy passwords
	    return false;
	}

	String hashedPassword = RanchSecurityUtil.encodeString(password + user.getSalt());
	if (hashedPassword.equals(user.getPassword())) {
	    return true;
	} else {
	    // try legacy method for backward compatibilty
	    hashedPassword = RanchSecurityUtil.encodeString2(password + user.getSalt());
	    if (hashedPassword.equals(user.getPassword())) {
		return true;
	    }
	}

	return false;
    }

    /**
     * @return the userDAO
     */
    public UserDAO getUserDAO() {
	return userDAO;
    }

    /**
     * @param userDAO
     *            the userDAO to set
     */
    public void setUserDAO(UserDAO userDAO) {
	this.userDAO = userDAO;
    }

    /**
     * @return the pearcorpUserDetailsService
     */
    public RanchUserDetailsService getMohrUserDetailsService() {
	return mohrUserDetailsService;
    }

    /**
     * @param mohrUserDetailsService
     *            the pearcorpUserDetailsService to set
     */
    public void setMohrUserDetailsService(
	    RanchUserDetailsService mohrUserDetailsService) {
	this.mohrUserDetailsService = mohrUserDetailsService;
    }

    @Override
    public User authenticateMobileUser(String username, String password) {
	
	User user = null;
	if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
	    user = userDAO.searchUniqueByPropertyEqual("username", username);
	    if (user != null && isValidUserPassword(user, password)) {
		    return user;
	    } else{
		user = null;
		return user;
	    }
	}
	return user;
    }
}
